package com.example.project_01.commons;

import lombok.Data;

import java.io.Serializable;

/**
 * ClassName: ApiResponse
 * Package: com.example.project_01.commons
 * Description:
 * 全局统一API响应模型
 * 规范：成功状态码用 2xx，客户端错误用 4xx，服务端错误用 5xx
 *
 * @Author ShiYi
 * @Create 2025/10/13 17:54
 * @Version 1.0
 */
@Data
// 泛型<T>，避免Object强转
public class ApiResponse<T> implements Serializable {
    // 序列化版本号
    private static final long serialVersionUID = 1L;

    /**
     * 响应状态码
     * - 200：请求成功（通用成功状态）
     * - 201：资源创建成功（新增用户、新增订单）
     * - 400：客户端参数错误（必填字段为空、格式不合法、用户名密码错误）
     * - 401：未登录/登录失效（需重新登录）
     * - 403：权限不足（已登录但无操作权限）
     * - 404：资源不存在（查询的用户ID不存在）
     * - 500：服务端内部错误（数据库异常、代码Bug）
     */
    private Integer code;

    /**
     * 响应提示信息
     * - 成功场景：简要说明结果（"登录成功"、"数据查询成功"）
     * - 失败场景：明确告知用户错误原因（"用户名或密码错误"、"手机号格式不合法"）
     */
    private String message;

    /**
     * 响应数据
     * 泛型<T>支持的场景：
     * - 成功且需返回数据：如用户信息（UserDTO）、列表数据（List<UserDTO>）、分页数据（PageResult）
     * - 成功无需返回数据：如删除操作，可设为 null 或空对象
     * - 失败场景：建议设为 null，避免前端解析冗余数据
     */
    private T data;

    /**
     * 响应时间戳
     * 作用：
     * - 前端可用于排查请求耗时（对比请求发送时间）
     * - 服务端日志排查时，可精准定位请求时间
     * 特点：创建对象时自动赋值，无需手动设置
     */
    private Long timestamp;

    // ==================== 无参构造器（默认初始化时间戳）====================
    public ApiResponse() {
        this.timestamp = System.currentTimeMillis(); // 自动填充当前时间（毫秒级）
    }

    // ==================== 全参构造器（用于自定义完整响应）====================
    public ApiResponse(Integer code, String message, T data) {
        this(); // 调用无参构造器，自动初始化时间戳
        this.code = code;
        this.message = message;
        this.data = data;
    }

    // ==================== 静态工厂方法（简化响应创建，避免重复new）====================

    /**
     * 通用成功响应（无数据返回）
     * 场景：删除操作、状态更新操作（如禁用用户）
     *
     * @return 成功响应（code=200，message="操作成功"，data=null）
     */
    public static <T> ApiResponse<T> success() {
        return new ApiResponse<>(200, "操作成功", null);
    }

    /**
     * 成功响应（带自定义提示信息，无数据返回）
     * 场景：需要个性化成功提示（如"登录成功"、"订单提交成功"）
     *
     * @param message 自定义成功提示
     * @return 成功响应（code=200，data=null）
     */
    public static <T> ApiResponse<T> success(String message) {
        return new ApiResponse<>(200, message, null);
    }

    /**
     * 成功响应（带数据返回，默认提示"操作成功"）
     * 场景：查询操作、创建操作（如查询用户列表、新增用户返回用户信息）
     *
     * @param data 响应数据（如UserDTO、List<UserDTO>）
     * @return 成功响应（code=200，message="操作成功"）
     */
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "操作成功", data);
    }

    /**
     * 成功响应（带自定义提示信息和数据返回）
     * 场景：需要个性化提示+数据返回（如"登录成功，返回用户信息"）
     *
     * @param message 自定义成功提示
     * @param data    响应数据
     * @return 成功响应（code=200）
     */
    public static <T> ApiResponse<T> success(String message, T data) {
        return new ApiResponse<>(200, message, data);
    }

    /**
     * 自定义状态码的成功响应（特殊场景）
     * 场景：资源创建成功（需返回201状态码，符合RESTful规范）
     *
     * @param code    自定义成功状态码（如201）
     * @param message 提示信息
     * @param data    响应数据（如创建的订单信息）
     * @return 自定义成功响应
     */
    public static <T> ApiResponse<T> successWithCode(Integer code, String message, T data) {
        // 校验状态码合法性：成功状态码必须是2xx开头
        if (code < 200 || code >= 300) {
            throw new IllegalArgumentException("成功状态码必须在 200-299 范围内");
        }
        return new ApiResponse<>(code, message, data);
    }

    /**
     * 客户端错误响应（4xx系列）
     * 场景：参数错误、未登录、登录失败、权限不足、资源不存在
     *
     * @param code    客户端错误状态码（如400、401、402、403、404）
     * @param message 错误原因提示
     * @return 客户端错误响应（data=null）
     */
    public static <T> ApiResponse<T> clientError(Integer code, String message) {
        // 校验状态码合法性：客户端错误必须是4xx开头
        if (code < 400 || code >= 500) {
            throw new IllegalArgumentException("客户端错误状态码必须在 400-499 范围内");
        }
        return new ApiResponse<>(code, message, null);
    }

    /**
     * 服务端错误响应（5xx系列，默认500）
     * 场景：数据库异常、代码Bug、第三方服务调用失败
     *
     * @param message 错误提示（避免返回技术细节，如"服务繁忙，请稍后重试"）
     * @return 服务端错误响应（code=500，data=null）
     */
    public static <T> ApiResponse<T> serverError(String message) {
        return new ApiResponse<>(500, message, null);
    }

    /**
     * 自定义服务端错误响应（特殊场景）
     * 场景：需要区分不同服务端错误（如503服务不可用）
     *
     * @param code    服务端错误状态码（如500、503）
     * @param message 错误提示
     * @return 自定义服务端错误响应
     */
    public static <T> ApiResponse<T> serverError(Integer code, String message) {
        // 校验状态码合法性：服务端错误必须是5xx开头
        if (code < 500 || code >= 600) {
            throw new IllegalArgumentException("服务端错误状态码必须在 500-599 范围内");
        }
        return new ApiResponse<>(code, message, null);
    }
}
